use std::fs;


const RAM_ORIGIN: u32 = 0x20000000 + 128;
const RAM_LENGTH: u32 = 20 * 1024 - 128;

const BOOT_ORIGIN: u32 = 0x08000000;
const BOOT_LENGTH: u32 = 8 * 1024;

const APP_ORIGIN: u32 = BOOT_ORIGIN + BOOT_LENGTH;
const APP_LENGTH: u32 = 24 * 1024;


/**
 * boot
 * 0x08000000 8k
 * app
 * 0x08000000
 */
struct Config {
    origin: u32,
    length: u32,
}

struct Memory {
    flash: Config,
    ram: Config,
    use_rtos: bool,
}

impl Memory {

    fn new(flash: Config, use_rtos: bool) -> Self {
        Self { flash, ram: Config { origin: RAM_ORIGIN, length: RAM_LENGTH }, use_rtos }
    }

    fn create(&self) {
        let provide = if self.use_rtos {
            r#"
PROVIDE(SysTick = SysTick_Handler);
PROVIDE(PendSV = PendSV_Handler);
PROVIDE(SVCall = SVC_Handler);
            "#
        } else {
            ""
        };

        let content = format!(r#"MEMORY 
{{
    FLASH : ORIGIN = 0x{:08x}, LENGTH = {}
    RAM : ORIGIN = 0x{:08x}, LENGTH = {}
}}
{}
    "#, self.flash.origin, self.flash.length, self.ram.origin, self.ram.length, provide);
        fs::write("./memory.x", content).unwrap();
    }
}

#[cfg(feature = "boot")]
fn create_memory() {
    let config = Memory::new(Config { origin: BOOT_ORIGIN, length: BOOT_LENGTH }, false);
    config.create();
}

#[cfg(feature = "app")]
fn create_memory() {
    let config = Memory::new(Config { origin: APP_ORIGIN, length: APP_LENGTH }, true);
    config.create();
}

fn main() {
    create_memory();
}
